<?php

declare(strict_types=1);

namespace app\service\system\file;

use owns\enum\CacheMap;
use think\facade\Cache;

class Captcha
{
    private $code; // 验证码
    private $codelen = 4; // 验证码长度
    private $codeText = 'number'; // 验证码文字
    private $width = 108; // 宽度
    private $height = 38; // 高度
    private $img; // 图形资源句柄
    private $font; // 指定的字体
    private $fontSize = 20; // 指定字体大小
    private $fontColor; // 指定字体颜色
    private $captchaId; // 图片ID
    private $base64Captcha; // 文件流
    /**
     * 字体路径
     */
    public function __construct()
    {
        $this->font = root_path() . '/file/ttf/Alibaba-PuHuiTi-Light.ttf';
    }
    /**
     * 生成背景
     */
    private function createBg(): void
    {
        $this->img = imagecreatetruecolor($this->width, $this->height);
        $color = imagecolorallocate($this->img, mt_rand(255, 255), mt_rand(255, 255), mt_rand(255, 255));
        imagefilledrectangle($this->img, 0, $this->height, $this->width, 0, $color);
    }
    /**
     * 生成文字
     */
    private function createFont(): void
    {
        $this->randomCode();
        $x = intval(($this->width - $this->codelen * $this->fontSize) / 2);
        foreach ($this->code as $i => $value) {
            $this->fontColor = imagecolorallocate($this->img, mt_rand(0, 99), mt_rand(0, 99), mt_rand(0, 99));
            $angle = mt_rand(-20, 20);
            if ($i) {
                $x += $this->fontSize;
            }
            $y = intval($this->height / 1.3);
            imagettftext($this->img, $this->fontSize, $angle, $x, $y, $this->fontColor, $this->font, $value);
        }
    }
    /**
     * 生成雪花
     */
    private function createLine(): void
    {
        for ($i = 0; $i < 18; $i++) {
            $color = imagecolorallocate($this->img, mt_rand(80, 235), mt_rand(80, 235), mt_rand(80, 235));
            imagestring($this->img, mt_rand(1, 5), mt_rand(2, $this->width - 2), mt_rand(2, $this->height - 2), '*', $color);
        }
    }
    /**
     * 图片输出
     */
    private function outPut(): void
    {
        ob_start();
        imagepng($this->img);
        imagedestroy($this->img);
        $this->base64Captcha = 'data:image/png;base64,' . base64_encode(ob_get_contents());
        ob_end_clean();
    }
    /**
     * 随机码
     */
    private function randomCode(): void
    {
        switch ($this->codeText) {
            case 'mixture':
                $num = 61;
                $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
                break;
            case 'capital':
                $num = 25;
                $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
                break;
            case 'lowercase':
                $num = 25;
                $chars = 'abcdefghijklmnopqrstuvwxyz';
                break;
            case 'number':
                $num = 9;
                $chars = '0123456789';
                break;
        }
        $this->code = [];
        for ($i = 0; $i < $this->codelen; $i++) {
            $this->code[] = $chars[mt_rand(0, $num)];
        }
    }
    /**
     * 验证码缓存 120 秒
     */
    private function buffer(): bool
    {
        $this->captchaId = unique_tag();
        return Cache::set(CacheMap::IMG_CAPTCHA . $this->captchaId, implode('', $this->code), 120);
    }
    /**
     * 生成图片
     */
    public function generate(): array
    {
        $this->createBg();
        $this->createLine();
        $this->createFont();
        $this->outPut();
        $this->buffer();
        return ['base64Captcha' => $this->base64Captcha, 'captchaId' => $this->captchaId];
    }
    /**
     * 验证
     * @param string $captchaId
     * @param string $captcha
     */
    public static function verify(string $captchaId, string $captcha): void
    {
        $cacheCaptcha = Cache::get(CacheMap::IMG_CAPTCHA . $captchaId);
        if (!$cacheCaptcha) {
            tips('验证码已失效');
        }
        if ($cacheCaptcha != $captcha) {
            tips('验证码不正确');
        }
        Cache::del(CacheMap::IMG_CAPTCHA . $captchaId);
    }
}
